using System;
using System.Windows.Input;
using Ausy.Silverlight.Survey.AccountModule.Model;
using Ausy.Silverlight.Survey.AccountModule.Services;
using Ausy.Silverlight.Survey.AccountModule.Services.ServiceEventArgs;
using Ausy.Silverlight.Survey.Infrastructure.Common;
using Ausy.Silverlight.Survey.Infrastructure.Events;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using Ausy.Silverlight.Survey.Infrastructure.Context;
using Ausy.Silverlight.Survey.Common.Validation;
using System.ComponentModel;

namespace Ausy.Silverlight.Survey.AccountModule.ViewParts
{
    /// <summary>
    /// Cette classe représente le Vue Model pour le CreateAccount
    /// </summary>
    public class CreateAccountViewModel : ViewModel<ICreateAccountView>, INotifyDataErrorInfo, ICreateAccountViewModel
    {
        #region Private Members

        /// <summary>
        /// Service de gestion des comptes utilisateur
        /// </summary>
        private IAccountService service;

        /// <summary>
        /// Gestionnaire de validation
        /// </summary>
        private ValidationManager validationManager;

        #endregion

        #region INotifyDataErrorInfo Members

        /// <summary>
        /// Evenement déclenché lors d'une érreur
        /// </summary>
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        private void RaiseErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }

        public System.Collections.IEnumerable GetErrors(string propertyName)
        {
            return this.validationManager.GetErrors(propertyName);
        }

        public bool HasErrors
        {
            get { return this.validationManager.HasErrors; }
        }

        #endregion
        
        #region AccountName Property
        /// <summary>
        /// Property name
        /// </summary>
        private string accountName;

        /// <summary>
        /// Property Name
        /// </summary>
        public string AccountName
        {
            get { return accountName; }
            set
            {
                if (accountName != value)
                {
                    accountName = value;
                    RaisePropertyChanged(() => this.AccountName);
                }
            }
        }

        #endregion
        
        #region AccountFirstName Property
        /// <summary>
        /// Property accountFirstName
        /// </summary>
        private string accountFirstName;

        /// <summary>
        /// Property AccountFirstName
        /// </summary>
        public string AccountFirstName
        {
            get { return accountFirstName; }
            set
            {
                if (accountFirstName != value)
                {
                    accountFirstName = value;
                    RaisePropertyChanged(() => this.AccountFirstName);
                }
            }
        }

        #endregion
        
        #region AccountEmail Property

        /// <summary>
        /// Property email
        /// </summary>
        private string accountEmail;

        /// <summary>
        /// Property Email
        /// </summary>
        public string AccountEmail
        {
            get { return accountEmail; }
            set
            {
                if (accountEmail != value)
                {
                    accountEmail = value;
                    RaisePropertyChanged(() => this.AccountEmail);
                }
            }
        }

        #endregion
        
        #region AccountPhone Property
        /// <summary>
        /// Property accountPhone
        /// </summary>
        private string accountPhone;

        /// <summary>
        /// Property AccountPhone
        /// </summary>
        public string AccountPhone
        {
            get { return accountPhone; }
            set
            {
                if (accountPhone != value)
                {
                    accountPhone = value;
                    RaisePropertyChanged(() => this.AccountPhone);
                }
            }
        }

        #endregion
        
        #region AccountCompany Property
        /// <summary>
        /// Property accountCompany
        /// </summary>
        private string accountCompany;

        /// <summary>
        /// Property AccountCompany
        /// </summary>
        public string AccountCompany
        {
            get { return accountCompany; }
            set
            {
                if (accountCompany != value)
                {
                    accountCompany = value;
                    RaisePropertyChanged(() => this.AccountCompany);
                }
            }
        }

        #endregion
        
        #region AccountFunction Property
        /// <summary>
        /// Property accountFunction
        /// </summary>
        private string accountFunction;

        /// <summary>
        /// Property AccountFunction
        /// </summary>
        public string AccountFunction
        {
            get { return accountFunction; }
            set
            {
                if (accountFunction != value)
                {
                    accountFunction = value;
                    RaisePropertyChanged(() => this.AccountFunction);
                }
            }
        }

        #endregion
        
        #region AccountExperience Property
        /// <summary>
        /// Property accountExperience
        /// </summary>
        private string accountExperience;

        /// <summary>
        /// Property AccountExperience
        /// </summary>
        public string AccountExperience
        {
            get { return accountExperience; }
            set
            {
                if (accountExperience != value)
                {
                    accountExperience = value;
                    RaisePropertyChanged(() => this.AccountExperience);
                }
            }
        }

        #endregion
        
        #region ValidateCommand Command Property

        /// <summary>
        /// Commande de valider la création d'un compte
        /// </summary>
        public ICommand ValidateCommand { get; private set; } 

        #endregion

        
        #region Constructor

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        /// <param name="container">Container Unity pour instanciation des type d'objet</param>
        public CreateAccountViewModel(IUnityContainer container)
            : base(container)
        {

        }

        #endregion

        #region Initialize Method

        /// <summary>
        /// Cette méthode permet l'initialisation du ViewModel avant que le DataContext soit affecté à la vue
        /// </summary>
        protected override void Initialize()
        {
            // Initialisation des Validateurs
            this.InitializeValidation();

            // Initialisation des commandes
            this.ValidateCommand = new DelegateCommand<string>(this.OnValidate);

        }

        #endregion

        #region InitializeValidation Method

        /// <summary>
        /// Initialisation de la validation
        /// </summary>
        private void InitializeValidation()
        {
            this.validationManager = new ValidationManager(RaiseErrorsChanged);
            this.validationManager.SetRuleFor(() => this.AccountName, new RequiredStringValidator(), "Le Nom est obligatoire !");
            this.validationManager.SetRuleFor(() => this.AccountFirstName, new RequiredStringValidator(), "Le prénom est obligatoire !");
            this.validationManager.SetRuleFor(() => this.AccountEmail, new RequiredStringValidator(), "L'email est obligatoire !");
            this.validationManager.SetRuleFor(() => this.AccountPhone, new RequiredStringValidator(), "Le téléphone est obligatoire !");
            this.validationManager.SetRuleFor(() => this.AccountEmail, new MailValidator(), "L'email est incorrect !");
            this.validationManager.SetRuleFor(() => this.AccountPhone, new PhoneValidator(), "Le téléphone est incorrect !");
           
            this.PropertyChanged += new PropertyChangedEventHandler(CreateAccountViewModel_PropertyChanged);
        }
         
        void CreateAccountViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.validationManager.ValidateRules(e.PropertyName);
        }


        #endregion

        #region OnValidate Method

        /// <summary>
        /// Cette méthode permet de valider le compte
        /// </summary>
        /// <param name="arg">empty</param>
        public void OnValidate(string arg)
        {
            this.validationManager.ValidateAllRules();

            if (!this.HasErrors)
            {
                // Initialisation des commandes
                this.service = this.container.Resolve<IAccountService>();
                this.service.CreateAccountCompleted += new EventHandler<AccountEventArgs>(this.OnCreateAccountCompleted);

                // Creation d'une instance account
                var account = this.container.Resolve<Account>();

                account.LastName = this.AccountName;
                account.FirstName = this.AccountFirstName;
                account.Email = this.AccountEmail;
                account.Function = this.AccountFunction;
                account.CompanyName = this.AccountCompany;
                account.Experience = this.AccountExperience;
                account.Phone = this.AccountPhone;

                // Appel du service
                this.service.CreateAccountAsync(account);
            }
        }

        #endregion

        #region OnCreateAccountCompleted Method

        /// <summary>
        /// Cette méthode permet de traiter le retour de création d'un utilisateur
        /// </summary>
        /// <param name="args">arguement du compte</param>
        public void OnCreateAccountCompleted(object sender, AccountEventArgs args)
        {
            var context = this.container.Resolve<IApplicationContext>();
            if (args != null)
            {
                // Lance le Questionnaire
                if (!args.AlreadyExist)
                {
                    context.AccountIdentifier = args.Account.Identifier;
                    context.AccountEmail = args.Account.Email;
                    this.eventAggregator.GetEvent<NavigateEvent>().Publish(new NavigateEvent(NavigateUri.QuestionnaireUri));
                }
                else
                {
                    context.AccountIdentifier = Guid.Empty;
                    context.AccountEmail = string.Empty;
                    this.eventAggregator.GetEvent<NavigateEvent>().Publish(new NavigateEvent(NavigateUri.ExistingAccountUri));
                }
            }
        } 

        #endregion

       
    }
}
